package edu.hawaii.duedates;

// The reference libraries coupled to DueDates.
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;
import edu.hawaii.duedates.messenger.Email;
import edu.hawaii.duedates.messenger.Messenger; 
import edu.hawaii.duedates.messenger.IMessenger.MessageType;
import edu.hawaii.duedates.user.User; 
import edu.hawaii.duedates.book.Book;
import edu.hawaii.duedates.book.DueDateComparator;
import edu.hawaii.duedates.book.LibraryComparator;
import edu.hawaii.duedates.book.TitleComparator;
import edu.hawaii.duedates.library.ILibrariesExtension;
import edu.hawaii.duedates.library.Library;

/**
 * The DueDates class accesses a given library for a given user to acquire the checked out items
 * information. DueDates receives arguments from the command line that include the library to
 * request information from, and the user id and the password belonging to required to log in to the
 * library's public web site.
 * 
 * DueDates works with the University of Hawaii and Hawaii State Library systems.
 * 
 * New Teammembers: Vincent Leung, Creighton Okada, John Zhou
 * 
 * @author Ronn Reeves and Robin E. Raqueno
 */
public final class DueDates implements Serializable {
  /** Unique identifier for this instance. */
  private static final long serialVersionUID = 1L;

  /**
   * Valid output options for the Messenger class.
   */
  public enum SortType {
    /** Sort by due date (default). */
    DUE_DATE,

    /** Sort by library item belongs to. */
    LIBRARY,

    /** Sort by book title. */
    TITLE;
  }

  /** Wakeup interval of running the program parameter. */
  // private double interval = new Double(0);
  /** Library collection. */
  private List<Library> libraries;

  /** Library being queried. */
  private Library library;

  /** The output message. */
  private final Messenger msg;

  /** SMTP server parameter. */
  private String smtpServer = "";

  /** User's email address. */
  private String userEmail = "";

  /** Within days of being due parameter. */
  private int within = 0;

  /** User object. */
  private User user;

  /** Book collection. */
  private List<Book> books;

  /**
   * Creates a new instance of this class.
   */
  public DueDates() {
    this.msg = new Messenger();
    msg.append(MessageType.SIMPLE, "Hello");
  }

  /**
   * Parses the unmatchedArgs to get the libraries to query from the library repository, and the
   * users for whom to query for.
   * 
   * @param libraries The library repository.
   * @param args The libraries passed from the command line.
   * 
   * @return UserLibraryInfo The UserLibraryInfo object holding the user library pairs.
   */
  /*
   * private UserLibraryInfo createUserLibraryPairs() { UserLibraryInfo uli = new UserLibraryInfo();
   * return uli; }
   */

  /**
   * Requests info from the libraries.
   */
  /*
   * private void requestData() { // Request library information.
   * msg.append(MessageType.REQUEST_DATA); uli.requestInfo();
   * 
   * // Display sorted books within the given due date period. msg.append(MessageType.SIMPLE,
   * uli.createReport(sortOption, withinDays)); }
   */

  /**
   * Reports the output of this query.
   */
  /*
   * void report() { //msg.report(this.emailAccount, this.smtpServer); this.msg.report(); }
   */

  /**
   * Outputs due dates to a string.
   * 
   * @return A string representing this DueDates instance.
   */
  public String toString() {
    return msg.toString();
  }

  /**
   * Queries the libraries at a given interval of time.
   * 
   * @param args The new set of arguments.
   * @param interval The interval period for querying data.
   */
  /*
   * private void wakeUp(String[] args, double interval) { // Amount of milliseconds in a day. final
   * int MILLISECOND_DAY = 1000 60 60 24 1; if (interval == 0) { this.requestData(); this.report();
   * }
   * 
   * else { String[] timerArgs = wakeUpArgs(args); Calendar cal = Calendar.getInstance(Locale.US);
   * int val = (int) (interval MILLISECOND_DAY); DueDatesTimerTask dt = new
   * DueDatesTimerTask(timerArgs); Timer timer = new Timer(); timer.schedule(dt, cal.getTime(),
   * val); } }
   */

  /**
   * This will stored the arguments in a new array.
   * 
   * @param args The arguments to be stored
   * @return newArgs The set of new arguments.
   */
  /*
   * private String[] wakeUpArgs(String[] args) { String[] newArgs = new String[args.length];
   * 
   * for (int i = 0; i < args.length; i++) { if ("-wakeup".equals(args[i])) { args[i + 1] = "0"; }
   * newArgs[i] = args[i]; }
   * 
   * return newArgs; }
   */

  /**
   * Sets the value of smtpServer.
   * 
   * @param value The smtpServer.
   */
  public void setSmtpServer(String value) {
    this.smtpServer = value;
  }

  /**
   * Sets the value of User.
   * 
   * @param value The User.
   */
  public void setUser(User value) {
    this.user = value;
  }

  /**
   * Sets the value of Library.
   * 
   * @param value The Library.
   */
  public void setLibrary(List<Library> value) {
    this.libraries = value;
  }

  /**
   * Gets the value of the smtpServer.
   * 
   * @return The smtpServer.
   */
  public String getSmtpServer() {
    return this.smtpServer;
  }

  /**
   * Gets the value of the User.
   * 
   * @return The User.
   */
  public User getUser() {
    return this.user;
  }

  /**
   * Gets the libraries.
   * 
   * @return The list of libraries.
   */
  public List<Library> getLibraries() {
    return this.libraries;
  }

  /**
   * Gets the books.
   * 
   * @return The books.
   */
  public List<Book> getBooks() {
    return this.books;
  }

  /**
   * Sets the books.
   * 
   * @param books The list of current books.
   */
  public void setBooks(List<Book> books) {
    this.books = books;
  }

  /**
   * Requestinfo method returns a list of books from the given Library list and within parameter.
   * 
   * @throws Exception Error with login.
   */
  public void requestInfo() throws Exception {
    this.books = new ArrayList<Book>();

    ILibrariesExtension libraryclass = (ILibrariesExtension) (Class.forName(this.library
        .getLocation()).newInstance());
    libraryclass.getInfo(this.library.getLogin(), this.library.getPassword(), books);

    Calendar cal = Calendar.getInstance();
    cal.add(Calendar.DAY_OF_MONTH, this.within);

    for (int i = 0; i < this.books.size(); i++) {
      int compare = cal.compareTo(this.books.get(i).getDueDate());
      if (compare > 0) {
        this.books.remove(i);
      }
    }
  }

  /**
   * Sets the value of User's email address.
   * 
   * @param email The email address.
   */
  public void setEmail(String email) {
    this.userEmail = email;
  }

  /**
   * Gets the value of the User's email address.
   * 
   * @return The User's email address.
   */
  public String getEmail() {
    return userEmail;
  }

  /**
   * This emails the list of books to the given email address.
   * 
   * @return true if the email was sent and false otherwise.
   */
  public Boolean emailUser() {

    try {
      Email email = new Email(userEmail, smtpServer, msg.toString());
      email.send();
      return true;
    }
    catch (Exception e) {
      return false;
    }

    /*
     * Properties props = new Properties(); String from = "ics413test@gmail.com"; String subject =
     * "Test E-Mail through Java"; props.put("mail.smtp.host", smtpServer);
     * 
     * Session session = Session.getInstance(props);
     * 
     * try { Message msg = new MimeMessage(session); msg.setFrom(new InternetAddress(from));
     * InternetAddress[] address = { new InternetAddress(userEmail) };
     * msg.setRecipients(Message.RecipientType.TO, address); msg.setSubject(subject);
     * msg.setSentDate(new Date()); msg.setText(message); Transport.send(msg); return true; } catch
     * (MessagingException mex) { mex.printStackTrace(); return false; }
     */
  }

  /**
   * Sets the value of within period.
   * 
   * @param within The period to query within (in days).
   */
  public void setWithin(int within) {
    this.within = within;
  }

  /**
   * Gets the value of within period.
   * 
   * @return The period to query within (in days).
   */
  public int getWithin() {
    return this.within;
  }

  /**
   * Sorts book list according to sort option.
   * @param  sortOption The book field to sort the books list by.
   */
  public void sort(SortType sortOption) {
    if (sortOption.equals(SortType.DUE_DATE)) {
      Collections.sort(books, new DueDateComparator());
    }
    else if (sortOption.equals(SortType.LIBRARY)) {
      Collections.sort(books, new LibraryComparator());
    }
    else if (sortOption.equals(SortType.TITLE)) {
      Collections.sort(books, new TitleComparator());
    }
  }

  /**
   * Sets the selected status of this library.
   * 
   * @param library The library.
   * @param selected The selected status.
   */
  public void setSelected(Library library, Boolean selected) {
    library.setSelected(selected);
  }

  /**
   * Gets the selected status of this library.
   * 
   * @param library The library.
   * @return True if selected.
   */
  public Boolean getSelected(Library library) {
    return library.getSelected(library);
  }

  /**
   * Sets the library to query.
   * 
   * @param library The library.
   */
  public void setLibrary(Library library) {
    this.library = library;
    try {
      requestInfo();
    }
    
    catch (Exception e) {
      this.msg.append(MessageType.SIMPLE, "Error retrieving data from this library.");
    }
  }

  /**
   * Gets the library being queried.
   * 
   * @return The library.
   */
  public Library getLibrary() {
    return this.library;
  }

  /**
   * Appends the books into the messenger.
   */
  public void createMessage() {
    String s = "";
    for (int i = 0; i <= books.size(); i++) {
      s = books.get(i).getLibrary() + books.get(i).getTitle() + books.get(i).getDueDate();
      msg.append(MessageType.SIMPLE, s);
    }
  }
}